package cloud.seri.iot.manager.service

import cloud.seri.iot.common.model.QueryDeviceDTO
import cloud.seri.iot.manager.client.DeviceManagerClient
import cloud.seri.iot.manager.domain.Aisle
import cloud.seri.iot.manager.domain.Device
import cloud.seri.iot.manager.domain.Product
import cloud.seri.iot.manager.domain.QDevice
import cloud.seri.iot.manager.repository.DeviceRepository
import cloud.seri.iot.manager.repository.ProductRepository
import cloud.seri.iot.manager.service.dto.DeviceDTO
import cloud.seri.iot.manager.service.dto.DeviceStatisticsDTO
import cloud.seri.iot.manager.service.example.DeviceExample
import cloud.seri.iot.manager.service.mapper.DeviceMapper
import net.dreamlu.mica.core.result.R
import org.slf4j.LoggerFactory
import org.springframework.data.domain.Example
import org.springframework.data.domain.ExampleMatcher
import org.springframework.data.mongodb.core.query.Criteria
import org.springframework.data.mongodb.datatables.DataTablesInput
import org.springframework.data.mongodb.datatables.DataTablesOutput
import org.springframework.stereotype.Service
import javax.annotation.PostConstruct

/**
 * Service Implementation for managing [Device].
 */
@Service
class DeviceService(
    val deviceRepository: DeviceRepository,
    val deviceMapper: DeviceMapper,
    val productRepository: ProductRepository,
    val client: DeviceManagerClient
)
{

    private val log = LoggerFactory.getLogger(DeviceService::class.java)


//    @PostConstruct
//    fun getDevicesByAliyun()
//    {
//        val pl = productRepository.findAll()
//        pl.forEach {
//            val res = client.queryDevice(it.productKey!!, 50, 1)
//            if (res.success)
//            {
//                res.data.forEach {
//                    val device = deviceMapper.deviceInfoToEntity(it)
//                    deviceRepository.save(device)
//                }
//
//            }
//        }
//    }

    /**
     * Save a device.
     *
     * @param deviceDTO the entity to save.
     * @return the persisted entity.
     */
    fun save(deviceDTO: DeviceDTO): DeviceDTO
    {
        log.debug("Request to save Device : {}", deviceDTO)

        var device = deviceMapper.toEntity(deviceDTO)
        device = deviceRepository.save(device)
        return deviceMapper.toDto(device)
    }

    fun createDevice(deviceDTO: DeviceDTO): R<DeviceDTO>
    {
        client.registerDevice(deviceMapper.deviceToRegisterDTO(deviceDTO))?.let {
            return if (it.success)
            {
                var device = deviceMapper.toEntity(deviceDTO)
                device.iotId = it.data.iotId
                device.deviceSecret = it.data.deviceSecret
                device.aisles = mutableListOf()
                for (i in 1..device.aisleCount)
                {
                    device.aisles?.add(Aisle(i, 0, null))
                }
                device = deviceRepository.save(device)
                R.success(deviceMapper.toDto(device))
            }
            else
            {
                R.fail(it.errorMessage)
            }
        }
        return R.fail("注册设备失败")
    }

    /**
     * Get all the devices.
     *
     * @return the list of entities.
     */
    fun findAll(): MutableList<DeviceDTO>
    {
        log.debug("Request to get all Devices")
        return deviceRepository.findAll()
            .mapTo(mutableListOf(), deviceMapper::toDto)
    }

    /**
     * Get one device by id.
     *
     * @param id the id of the entity.
     * @return the entity.
     */
    fun findOne(id: String): R<DeviceDTO>
    {
        log.debug("Request to get Device : {}", id)
        val response = client.queryDeviceDetail(id)
        return if (response?.success == true)
        {
            var dev = deviceMapper.deviceDetailDataToEntity(response.data)
            deviceRepository.findById(id).ifPresent {
                it.createdDate = dev.createdDate
                it.status = dev.status
                it.onlineDate = dev.onlineDate
                it.activeDate = dev.activeDate
                dev = deviceRepository.save(it)
            }
            R.success(deviceMapper.toDto(dev))
        }
        else
        {
            R.fail(response?.errorMessage)
        }
    }

    /**
     * Delete the device by id.
     *
     * @param id the id of the entity.
     */
    fun delete(id: String): R<Void>?
    {
        log.debug("Request to delete Device : {}", id)
        val res = client.deleteDevice(id)
        return if (res.success)
        {
            deviceRepository.deleteById(id)
            R.success<Void>()
        }
        else
        {
            R.fail(res.errorMessage)
        }

    }

    fun getDevices(pk: String?, input: DataTablesInput): DataTablesOutput<DeviceDTO>
    {
        if (!pk.isNullOrBlank())
        {
            return deviceMapper.toDataTablesOutput(deviceRepository.findAll(input, Criteria.where("product.\$id").`is`(pk)))
        }
        return deviceMapper.toDataTablesOutput(deviceRepository.findAll(input))
    }

    fun queryDeviceStatistics(pk: String?): R<DeviceStatisticsDTO>?
    {
        val dto = DeviceStatisticsDTO()
        val device = QDevice.device
        if (!pk.isNullOrBlank())
        {
            val example = device.product.productKey.eq(pk)
            dto.deviceCount = deviceRepository.count(example)
            dto.activeCount = deviceRepository.count(example.and(device.status.notIn(2)))
            dto.onlineCount = deviceRepository.count(example.and(device.status.eq(0)))
        }
        else
        {
            dto.deviceCount = deviceRepository.count()
            dto.activeCount = deviceRepository.count(device.status.notIn(2))
            dto.onlineCount = deviceRepository.count(device.status.eq(0))
        }

        return R.success(dto)
    }
}
